/*
 * L9Store.h
 *
 *  Created on: 2011-10-18
 *      Author: baixp
 */

#ifndef L9STORE_H_
#define L9STORE_H_
#include <FBase.h>
#include <FIo.h>
using namespace Osp::Base;
using namespace Osp::Io;
#include "L9InputStream.h"
#include "L9OutputStream.h"
#include "L9Http.h"
#include "L9Util.h"
#include <fstream>
using namespace std;
namespace lib9bada {
class L9Store {
private:
	int _mode;
	String _storeName;
	L9OutputStream* _out;
	L9InputStream* _in;
	L9Http* _http;
	pByte _head;
	bool _bInSaving;
	void _initStore(String storeName, int mode, byte* head, int off, int size) {
		defaultInit();
		_storeName = storeName;
		_mode = mode;

		setHead(head, off, size);

		switch (_mode) {
		case K_Store_Mode_Write:
			_out = new L9OutputStream();
			break;
		case K_Store_Mode_Write_Url:
			_out = new L9OutputStream();
			_http = new L9Http();
			break;
		case K_Store_Mode_Read: {
			int size = -1;
			byte* sFile = L9Util::getCStringN(_storeName);
			//处理文件不存在的情况
			byte* bin = L9Util::getFileBin((char*) sFile, size);
			if (bin != null && size > 0) {
				_in = new L9InputStream(bin, 0, size);
				if (bin != null) {
					delete[] bin;
					bin = null;
				}
			}
			if (sFile != null) {
				delete[] sFile;
				sFile = null;
			}
		}
			break;
		case K_Store_Mode_Read_Url:
			_http = new L9Http();
			_http->openHttp(_storeName, head, off, size); // 开启线程
		}
	}
	void writeBytesIntoFile(String sFile, char* bin, int len) {
		File file;
		ByteBuffer buf;
		file.Construct(sFile, L"w+");
		file.Write(bin, len);
	}
	void defaultInit() {
		_out = null;
		_in = null;
		_http = null;
		_bInSaving = false;
	}
public:
	L9Store();
	virtual ~L9Store();
	/**
	 * 普通的存储模式写
	 */
	static const int K_Store_Mode_Write = 0;
	/**
	 * 网络存储模式写
	 */
	static const int K_Store_Mode_Write_Url = 1;
	/**
	 * 普通的存储模式读
	 */
	static const int K_Store_Mode_Read = 2;
	/**
	 * 网络的存储模式读
	 */
	static const int K_Store_Mode_Read_Url = 3;

	/**
	 * 进行联网存储时有时需要设置一些头信息，这样便于服务器来处理数据
	 *@param byte* head
	 *@param int off
	 *@param int size
	 */
	void setHead(byte* head, int off, int size) {
		_head.pChar = new byte[size];
		_head.size = size;
		L9Util::System_arraycopy(head, off, _head.pChar, 0, size);
	}

	/**
	 * 根据存储名称和模式来创建一个存储，总共有5个参数，分别是存储名(有可能是url)、模式、头信息、代理、连接超时
	 * 注意当进行数据的写操作后，需要调用Save方式才能最后保存进存储中
	 * 注意存储名称可能为url地址，比如：http://www.lib9.net/storetest.aspx,这要根据mode来决定
	 * head是存储操作时向服务器发送的头数据，服务器可以根据这些数据来进行相应的处理
	 * sAgent默认为10.0.0.172:80,当需要使用代理联网，并且代理不是10.0.0.172:80时则需要设置sAgent
	 * timeout默认是45秒，这个是第一次联网判断接入点的时间,如果timeout为-1则不判断联网接入点直接联网(如果接入点是不对将连接不上)
	 *
	 * @param storeName
	 *            String
	 * @param mode
	 *            int
	 * @param head
	 *            byte[]
	 * @param sAgent
	 *            String
	 * @param timeout
	 *            int
	 */
	L9Store(String storeName, int mode, byte* head, int off, int headSize) {
		_initStore(storeName, mode, head, off, headSize);
	}

	/**
	 * 根据存储名和模式来创建存储，如果是联网存储则使用联网默认设置(默认第一个判断接入点和默认代理)
	 *
	 * @param storeName
	 *            String
	 * @param mode
	 *            int
	 */
	L9Store(String storeName, int mode) {
		_initStore(storeName, mode, null, 0, 0);
	}

	/**
	 * 往存储写入一个布尔值
	 *
	 * @param b
	 *            bool
	 */
	void writeBoolean(bool b) {
		_out->writeBoolean(b);
	}

	/**
	 * 往存储写入一个Byte字节
	 *
	 * @param bt
	 *            byte
	 */
	void writeByte(char bt) {
		_out->writeByte(bt);
	}

	/**
	 * 将字节数组的一部分，偏移量off开始取len长度的字节写入存储
	 *
	 * @param arr
	 *            byte[]
	 * @param off
	 *            int
	 * @param len
	 *            int
	 */
	void writeBytes(byte* arr, int off, int len) {
		_out->writeBytes(arr, off, len);
	}

	/**
	 * 往存储写入一个short值，占两个字节
	 *
	 * @param s
	 *            short
	 */
	void writeShort(short s) {
		_out->writeShort(s);
	}

	/**
	 * 往存储写入一个int值，占4个字节
	 *
	 * @param s
	 *            int
	 */
	void writeInt(int s) {
		_out->writeInt(s);
	}

	/**
	 * 往存储写入一个long值,占8个字节
	 *
	 * @param s
	 *            long
	 */
	void writeLong(long s) {
		_out->writeLong(s);
	}

	//	/**
	//	 * 按照指定的编码将字符串写入存储中
	//	 *
	//	 * @param pStr
	//	 *            String
	//	 * @param Encode
	//	 *            String
	//	 */
	//	void writeString(String pStr, String Encode) {
	//		_out->writeString(pStr, Encode);
	//	}

	/**
	 * 按UTF-8编码将字符串写入存储中
	 *
	 * @return String
	 */
	void writeString(String pStr) {
		_out->writeString(pStr);
	}

	/**
	 * 保存存储，当进行完所有的写操作后需要调用该方法来保存储存
	 */
	void Save() {
		switch (_mode) {
		case K_Store_Mode_Write: {
			byte*pName = L9Util::getCStringN(_storeName);
			byte*pBin = _out->getBytesN();
			L9Util::wirteFileBin((char*) pName, pBin);
			if (pName != null) {
				delete[] pName;
				pName = null;
			}
			if (pBin != null) {
				delete[] pBin;
				pBin = null;
			}
		}
			break;
		case K_Store_Mode_Write_Url: {
			_bInSaving = true;
			byte*pBin = _out->getBytesN();
			byte*bin = null;
			if (_head.pChar != null) {
				bin = L9Util::mergeBytes(_head.pChar, _head.size, pBin,
						_out->getOff());
			}
			_http->openHttp(_storeName, bin, 0, _head.size + _out->getOff()); // 开启线程
			//注意这里是多线程，可能下面的语句有问题，有时间了来仔细处理
			if (pBin != null) {
				delete[] pBin;
				pBin = null;
			}
			if (bin != null) {
				delete[] bin;
				bin = null;
			}
		}
		}
	}
	/**
	 * 返回是否正在处理中
	 * @return bool
	 */
	bool isInProcess() {
		return _http->isInProcess();
	}

	/**
	 * 返回http连接过程是否有错误发生
	 *
	 * @return bool
	 */
	bool isError() {
		return _http->isError();
	}

	// ////////////////////////////////////////////////////////读模式/////////////////////////////////////
	/**
	 * 从存储中读出一个布尔值
	 * @return bool
	 */
	bool readBoolean() {
		return _in->readBoolean();
	}

	/**
	 * 从存储中读出一个byte字节
	 * @return byte
	 */
	byte readByte() {
		return _in->readByte();
	}

	/**
	 * 从存储中读取一个byte字节返回为int值，参数bSigned为true表示有符号数,否则为无符号数，readByte(true)
	 * 等于readByte()
	 *
	 * @param bSigned
	 *            bool
	 * @return int
	 */
	int readByte(bool bSigned) {
		return _in->readByte(bSigned);
	}

	/**
	 * 从存储中读出len长度的字节数组
	 * @param len int
	 * @return byte[]
	 */
	byte* readBytesN(int len) {
		return _in->readBytesN(len);
	}

	/**
	 * 从存储中读出一个short值，占两个字节
	 * @return short
	 */
	short readShort() {
		return _in->readShort();
	}

	/**
	 * 从存储中读出一个int值，占4个字节
	 * @return int
	 */
	int readInt() {
		return _in->readInt();
	}

	/**
	 * 从存储中读出一个long值，占8个字节
	 * @return long
	 */
	long readLong() {
		return _in->readLong();
	}

	//	/**
	//	 * 按照指定的编码从存储中读出字符串
	//	 *
	//	 * @param Encode
	//	 *            String
	//	 * @return String
	//	 */
	//	String readString(String Encode) {
	//		return _in->readString(Encode);
	//	}

	/**
	 * 按UTF-8编码来从存储中读取字符串
	 *
	 * @return String
	 */
	String readString() {
		return _in->readString();
	}

	/**
	 * 跳过nBytes个字节
	 * @param nBytes int
	 */
	void Skip(int nBytes) {
		_in->skipBytes(nBytes);
	}

	/**
	 * 如果是联网存储，需要调用该函数判断是否已经准备存储了，如果是读模式只有该函数返回true才能进行读操作，如果是写模式返回true表示已经保存完毕
	 *
	 * @return bool
	 */
	bool isReady() {
		switch (_mode) {
		case K_Store_Mode_Write_Url:
			if (_bInSaving && !isInProcess() && !isError()) { // 表示已经保存完毕
				_bInSaving = false;
				pByte data = _http->getData();
				if (data.pChar != null) {
					_in = new L9InputStream(data.pChar, 0, data.size);
				}
				return true;
			}
			break;
		case K_Store_Mode_Read_Url:
			if (!isInProcess() && !isError()) {
				if (_in == null) {
					pByte data = _http->getData();
					if (data.pChar != null) {
						_in = new L9InputStream(data.pChar, 0, data.size);
					}
				}
				return true;
			}
			break;
		case K_Store_Mode_Read:
			if (_in != null) {
				return true;
			}
			break;
		}
		return false;
	}
};
};

#endif /* L9STORE_H_ */
